package org.simp.core.head;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.log4j.Logger;
import org.simp.common.Constants;
import org.simp.exception.SimpIncompleteException;
import org.simp.protocol.core.SimpHead;
import org.simp.protocol.core.SimpHead.Head;
import org.simp.protocol.core.SimpHead.Paramter;

import com.google.protobuf.InvalidProtocolBufferException;

/**
 * @author zhuhaitao at 2014-5-21
 *
 * 消息头部
 */
public class Header implements SimpHeader {

	private static final Logger log = Logger.getLogger(Header.class);
	
	private Head header;
	
	/**目的地址**/
	private String objAddress;
	/**源地址**/
	private String srcAddress;
	
	private String version = Constants.VERSION ;//协议版本,默认1.0
	private short mainId;
	private short moudleId;
	private int contentLength;
	/**发送序号，需要等待返回的消息需要用到这个字段**/
	private int serial;
	/**消息类型，0:至多一次，1：只有一次**/
	private byte msgType;
	/**是否修改过**/
	private transient boolean hasModify ;
	
	Map<String,String> headParamMap = new HashMap<String,String>();
	
	public Head getHeader() {
		return header;
	}
	public void setHeader(Head header) {
		hasModify = true;
		this.header = header;
	}
	public String getObjAddress() {
		return objAddress;
	}
	public void setObjAddress(String objAddress) {
		hasModify = true;
		this.objAddress = objAddress;
	}
	public String getSrcAddress() {
		return srcAddress;
	}
	public void setSrcAddress(String srcAddress) {
		hasModify = true;
		this.srcAddress = srcAddress;
	}
	public String getVersion() {
		return version;
	}
	public void setVersion(String version) {
		hasModify = true;
		this.version = version;
	}
	public short getMainId() {
		return mainId;
	}
	public void setMainId(short mainId) {
		hasModify = true;
		this.mainId = mainId;
	}
	public short getMoudleId() {
		return moudleId;
	}
	public void setMoudleId(short moudleId) {
		hasModify = true;
		this.moudleId = moudleId;
	}
	public int getContentLength() {
		return contentLength;
	}
	public void setContentLength(int contentLength) {
		hasModify = true;
		this.contentLength = contentLength;
	}
	
	public int getSerial() {
		return serial;
	}
	public void setSerial(int serial) {
		this.serial = serial;
		hasModify = true;
	}

	
	public void addHeadParam(String key,String value){
		hasModify = true;
		this.headParamMap.put(key, value);
	}
	
	public void setHeadParam(String key,String value){
		hasModify = true;
		this.headParamMap.put(key, value);
	}
	public String getHeadParam(String key){
		return this.headParamMap.get(key);
	}
	
	public byte[] encode() throws SimpIncompleteException{
		createHeader();
		try{
		return this.header.toByteArray();
		}catch (Exception e) {
			throw new SimpIncompleteException("ENCODE SIMP HEAD ERROR ",e);
		}
	}
	private void createHeader() throws SimpIncompleteException{
		/**如果没有修改，就不用重新生成头部**/
		if(header != null && !hasModify){
			return ;
		}
		try{
		Head.Builder builder = Head.newBuilder();
		builder.setContentLength(contentLength);
		builder.setMainId(mainId);
		builder.setMoudleId(moudleId);
		if(serial >0)
		builder.setSerial(serial);
		builder.setSrcAddress(srcAddress);
		builder.setObjAddress(objAddress);
		builder.setVersion(version);
		builder.setMsgType(msgType);
		Set<String> keys = headParamMap.keySet();
		for(String key : keys){
			builder.addParamter(createParamter(key, headParamMap.get(key)));
		}
		this.header = builder.build();
		hasModify = false;
		}catch (Exception e) {
			log.warn("CREATE SIMP　HEAD ERROR ,NEED SOME PARAMS  ",e);
			throw new SimpIncompleteException();
		}
	}
	public void decode(byte [] data) throws SimpIncompleteException{
		try {
			this.header = Head.parseFrom(data);
			this.contentLength = header.getContentLength();
			this.mainId = (short) header.getMainId();
			this.moudleId = (short) header.getMoudleId();
			this.srcAddress = header.getSrcAddress();
			this.objAddress = header.getObjAddress();
			this.version = header.getVersion();
			this.msgType = (byte) header.getMsgType();
			if(header.hasSerial()){
				this.serial = header.getSerial();
			}
			headParamMap.clear();
			List<Paramter> list = header.getParamterList();
			for(Paramter p : list){
				headParamMap.put(p.getName(),p.getValue());
			}
			hasModify = false;
		} catch (InvalidProtocolBufferException e) {
			e.printStackTrace();
			throw new SimpIncompleteException(" DECODE SIMP HEAD ERROR ",e);
		}
	}
	
	private Paramter createParamter(String key,String value){
		SimpHead.Paramter.Builder  builder = SimpHead.Paramter.newBuilder();
		builder.setName(value);
		builder.setValue(value);
		return builder.build();
	}
	@Override
	public int getRequestId() {
		return ((mainId<<16) & 0xffffffff) | (moudleId & 0xffff);
	}
	@Override
	public void setRequestId(int requestId) {
		mainId = (short) ((requestId >> 16) & 0xffff);
		moudleId = (short)(requestId & 0xffff);
		hasModify = true;
	}
	
	public String toString(){
		StringBuffer sb = new StringBuffer();
		sb.append("objAddress: ").append(objAddress).append(Constants.ENTER);
		sb.append("srcAddress: ").append(srcAddress).append(Constants.ENTER);
		sb.append("mainId: ").append(mainId).append(Constants.ENTER);
		sb.append("moudleId: ").append(moudleId).append(Constants.ENTER);
		sb.append("version: ").append(version).append(Constants.ENTER);
		sb.append("contentLength: ").append(contentLength).append(Constants.ENTER);
		Set<String> keys = headParamMap.keySet();
		for(String key : keys){
			sb.append(key + ": ").append(headParamMap.get(key)).append(Constants.ENTER);
		}
		return sb.toString();
	}
	@Override
	public void setHeadParam(Map<String, String> paramMap) {
		this.headParamMap = paramMap;
	}
	@Override
	public Map<String, String> getHeadParam() {
		return headParamMap;
	}
	@Override
	public void setMsgType(byte msgType) {
		this.msgType = msgType;
	}
	@Override
	public byte getMsgType() {
		return msgType;
	}
}
